/*
 * This file is part of aion-engine <aion-engine.com>
 *
 * aion-engine is private software: you can redistribute it and or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Private Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * aion-engine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser Public License for more details.
 *
 * You should have received a copy of the GNU Lesser Public License
 * along with aion-engine.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.aionengine.gameserver.services;

import com.aionemu.commons.database.dao.DAOManager;
import com.aionengine.gameserver.configs.main.WeddingsConfig;
import com.aionengine.gameserver.dao.WeddingDAO;
import com.aionengine.gameserver.model.Wedding;
import com.aionengine.gameserver.model.gameobjects.player.Player;
import com.aionengine.gameserver.services.MuiService;
import com.aionengine.gameserver.services.item.ItemService;
import com.aionengine.gameserver.utils.PacketSendUtility;
import com.aionengine.gameserver.world.World;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @author synchro2
 */

public class WeddingService {

    private Map<Integer, Wedding> weddings = new HashMap<Integer, Wedding>();

    public static final WeddingService getInstance() {
        return SingletonHolder.instance;
    }

    public void registerOffer(Player partner1, Player partner2, Player priest) {
        if (!canRegister(partner1, partner2)) {
            PacketSendUtility.sendMessage(priest, MuiService.getInstance().getMessage("WEDDING_ALREADY_MARRIED"));
            return;
        }
        weddings.put(partner1.getObjectId(), new Wedding(partner1, partner2, priest));
        weddings.put(partner2.getObjectId(), new Wedding(partner2, partner1, priest));
    }

    private boolean canRegister(Player partner1, Player partner2) {
        return (getWedding(partner1) == null && getWedding(partner2) == null && !partner1.isMarried() && !partner2
                .isMarried());
    }

    public void acceptWedding(Player player) {
        Player partner = getPartner(player);
        Wedding playersWedding = getWedding(player);
        Wedding partnersWedding = getWedding(partner);

        playersWedding.setAccept();
        if (partnersWedding.isAccepted()) {
            if (!checkConditions(player, partner)) {
                cleanWedding(player, partner);
            } else {
                doWedding(player, partner);
                if (WeddingsConfig.WEDDINGS_GIFT_ENABLE) {
                    giveGifts(player, partner);
                }
                if (WeddingsConfig.WEDDINGS_ANNOUNCE) {
                    announceWedding(player, partner);
                }
            }
        }
    }

    private void doWedding(Player player, Player partner) {
        DAOManager.getDAO(WeddingDAO.class).storeWedding(player, partner);
        player.setPartnerId(partner.getObjectId());
        partner.setPartnerId(player.getObjectId());
        PacketSendUtility.sendMessage(player, MuiService.getInstance().getMessage("WEDDING_ADD_MARIED", partner.getName()));
        PacketSendUtility.sendMessage(partner, MuiService.getInstance().getMessage("WEDDING_ADD_MARIED", player.getName()));
        PacketSendUtility.sendMessage(getPriest(player), MuiService.getInstance().getMessage("WEDDING_CANCELED",  player.getName(), partner.getName()));
        cleanWedding(player, partner);
    }

    public void unDoWedding(Player player, Player partner) {
        DAOManager.getDAO(WeddingDAO.class).deleteWedding(player, partner);
        player.setPartnerId(0);
        partner.setPartnerId(0);
        PacketSendUtility.sendMessage(player, MuiService.getInstance().getMessage("WEDDING_CANCELED"));
        PacketSendUtility.sendMessage(partner, MuiService.getInstance().getMessage("WEDDING_CANCELED"));
    }

    private boolean checkConditions(Player player, Player partner) {
        if (player.isMarried() || partner.isMarried()) {
            PacketSendUtility.sendMessage(player, MuiService.getInstance().getMessage("WEDDING_ALREADY_MARIED"));
            PacketSendUtility.sendMessage(partner, MuiService.getInstance().getMessage("WEDDING_ALREADY_MARIED"));
            PacketSendUtility.sendMessage(getPriest(player), MuiService.getInstance().getMessage("WEDDING_ALREADY_MARIED"));
        }
        if (WeddingsConfig.WEDDINGS_SUIT_ENABLE) {
            String[] suits = WeddingsConfig.WEDDINGS_SUITS.split(",");
            boolean success1 = false;
            boolean success2 = false;
            try {
                for (String suit : suits) {
                    int suitId = Integer.parseInt(suit);
                    if (!player.getEquipment().getEquippedItemsByItemId(suitId).isEmpty()) {
                        success1 = true;
                    }
                    if (!partner.getEquipment().getEquippedItemsByItemId(suitId).isEmpty()) {
                        success2 = true;
                    }
                }
            } catch (NumberFormatException e) {
                e.printStackTrace();
            } finally {
                if (!success1 || !success2) {
                    PacketSendUtility.sendMessage(player, MuiService.getInstance().getMessage("WEDDING_NOT_EQUIP_SUIT"));
                    PacketSendUtility.sendMessage(partner, MuiService.getInstance().getMessage("WEDDING_NOT_EQUIP_SUIT"));
                    PacketSendUtility.sendMessage(getPriest(player), MuiService.getInstance().getMessage("WEDDING_NOT_EQUIP_SUIT"));
                    return false;
                }
            }
        }

        if (player.getKnownList().getObject(partner.getObjectId()) == null) {
            PacketSendUtility.sendMessage(player, MuiService.getInstance().getMessage("WEDDING_SOULD_SEE_SPOUSE"));
            PacketSendUtility.sendMessage(partner, MuiService.getInstance().getMessage("WEDDING_SOULD_SEE_SPOUSE"));
            PacketSendUtility.sendMessage(getPriest(player), MuiService.getInstance().getMessage("WEDDING_PLAYERS_NOT_SEE_SPOUSE"));
            return false;
        }

        if (!player.havePermission(WeddingsConfig.WEDDINGS_MEMBERSHIP)
                || !partner.havePermission(WeddingsConfig.WEDDINGS_MEMBERSHIP)) {
            PacketSendUtility.sendMessage(player, MuiService.getInstance().getMessage("WEDDING_REQUIRED_MEMBERSHIP"));
            PacketSendUtility.sendMessage(partner, MuiService.getInstance().getMessage("WEDDING_REQUIRED_MEMBERSHIP"));
            PacketSendUtility.sendMessage(getPriest(player), MuiService.getInstance().getMessage("WEDDING_REQUIRED_MEMBERSHIP"));
            return false;
        }

        if (!WeddingsConfig.WEDDINGS_SAME_SEX
                && player.getCommonData().getGender().equals(partner.getCommonData().getGender())) {
            PacketSendUtility.sendMessage(player, MuiService.getInstance().getMessage("WEDDING_SAME_SEX"));
            PacketSendUtility.sendMessage(partner, MuiService.getInstance().getMessage("WEDDING_SAME_SEX"));
            PacketSendUtility.sendMessage(getPriest(player), MuiService.getInstance().getMessage("WEDDING_SAME_SEX"));
            return false;
        }

        if (!WeddingsConfig.WEDDINGS_DIFF_RACES
                && !player.getCommonData().getRace().equals(partner.getCommonData().getRace())) {
            PacketSendUtility.sendMessage(player, MuiService.getInstance().getMessage("WEDDING_DIFFERENT_RACES"));
            PacketSendUtility.sendMessage(partner, MuiService.getInstance().getMessage("WEDDING_DIFFERENT_RACES"));
            PacketSendUtility.sendMessage(getPriest(player), MuiService.getInstance().getMessage("WEDDING_DIFFERENT_RACES"));
            return false;
        }

        if (WeddingsConfig.WEDDINGS_KINAH != 0) {
            if (!player.getInventory().tryDecreaseKinah(WeddingsConfig.WEDDINGS_KINAH)
                    || !partner.getInventory().tryDecreaseKinah(WeddingsConfig.WEDDINGS_KINAH)) {
                PacketSendUtility.sendMessage(player, MuiService.getInstance().getMessage("WEDDING_REQUIRED_KINAH"));
                PacketSendUtility.sendMessage(partner, MuiService.getInstance().getMessage("WEDDING_REQUIRED_KINAH"));
                PacketSendUtility.sendMessage(getPriest(player), MuiService.getInstance().getMessage("WEDDING_REQUIRED_KINAH"));
                return false;
            }
        }
        return true;
    }

    private void giveGifts(Player player, Player partner) {
        ItemService.addItem(player, WeddingsConfig.WEDDINGS_GIFT, 1);
        ItemService.addItem(partner, WeddingsConfig.WEDDINGS_GIFT, 1);
    }

    private void announceWedding(Player player, Player partner) {
        String message = MuiService.getInstance().getMessage("WEDDING_ANNOUNCE_MARIED", player.getName(), partner.getName());

        Iterator<Player> iter = World.getInstance().getPlayersIterator();
        while (iter.hasNext()) {
            PacketSendUtility.sendBrightYellowMessage(iter.next(), message);
        }
    }

    public void cancelWedding(Player player) {
        PacketSendUtility.sendMessage(player, MuiService.getInstance().getMessage("WEDDING_CANCELED"));
        PacketSendUtility.sendMessage(getPartner(player), MuiService.getInstance().getMessage("WEDDING_PLAYER_DECLINED_WEDDING", player.getName()));
        PacketSendUtility.sendMessage(getPriest(player), MuiService.getInstance().getMessage("WEDDING_PLAYER_DECLINED_WEDDING", player.getName()));
        cleanWedding(player, getPartner(player));
    }

    private void cleanWedding(Player player, Player partner) {
        weddings.remove(player.getObjectId());
        weddings.remove(partner.getObjectId());
    }

    public Wedding getWedding(Player player) {
        return weddings.get(player.getObjectId());
    }

    private Player getPartner(Player player) {
        Wedding wedding = weddings.get(player.getObjectId());
        return wedding.getPartner();
    }

    private Player getPriest(Player player) {
        Wedding wedding = weddings.get(player.getObjectId());
        return wedding.getPriest();
    }

    @SuppressWarnings("synthetic-access")
    private static class SingletonHolder {

        protected static final WeddingService instance = new WeddingService();
    }
}
